package com.ww.springboot.boot.utils;

import com.google.common.collect.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;

import java.util.List;
import java.util.concurrent.*;

public class ThreadPoolFactoryUtil {
    private volatile static ThreadPoolExecutor instance;
    private final static int THREAD_COUNTS = 8;
    private final static int THREAD_TASKS = 9999;
    private final static long KEEP_ALIVE_TIME = 1;

    static {
        // 注册jvm钩子函数，关闭线程池资源
        Runtime.getRuntime().addShutdownHook(new Thread(ThreadPoolFactoryUtil::close));
    }

    public static ThreadPoolExecutor getInstance() {
        if (instance == null) {
            synchronized (ThreadPoolFactoryUtil.class) {
                if (instance == null) {
                    instance = new ThreadPoolExecutor(
                            THREAD_COUNTS,
                            THREAD_COUNTS,
                            KEEP_ALIVE_TIME,
                            TimeUnit.MINUTES,
                            new LinkedBlockingQueue<>(THREAD_TASKS),
                            new CustomizableThreadFactory("thread-pool-util"));
                }
            }
        }
        return instance;
    }

    public static void close() {
        if (instance == null) {
            return;
        }
        instance.shutdown();
    }

    public static <T> void execute(List<T> lstVo, IRunnable<T> runnable, int pageSize) throws Exception {
		List<Callable<Boolean>> tasks = Lists.newArrayList();
		int pageNumber = 1;
		int totalPage = lstVo.size() % pageSize > 0 ? lstVo.size() / pageSize + 1 : lstVo.size() / pageSize;
		for (; pageNumber <= totalPage; pageNumber++) {
			//线程池切割任务, 每个任务最多查询pageSize个账号的数据
			tasks.add(new BaseCallable(runnable, lstVo.subList((pageNumber - 1) * pageSize,
				Math.min(pageNumber * pageSize, lstVo.size()))));
		}

		List<Future<Boolean>> allResults = getInstance().invokeAll(tasks);
		//等待所有任务执行完成后获取所有返回结果
		for (Future<Boolean> ft : allResults) {
			Boolean r = ft.get();
			if (!r) {
				throw new Exception("thread-pool-util.execute.failed");
			}
		}
	}

	public static class BaseCallable implements Callable<Boolean> {
		private static final Logger log = LoggerFactory.getLogger(BaseCallable.class);
		IRunnable runnable;
		List subList;

		public BaseCallable(IRunnable runnable, List subList) {
			this.runnable = runnable;
			this.subList = subList;
		}

		@Override
		public Boolean call() throws Exception {
			try {
				return this.runnable.call(this.subList);
			} catch (Exception var2) {
				log.error("线程池任务异常!", var2);
				return false;
			}
		}
	}



}
